from opencv.cv import *
from opencv.highgui import *
import AiImage

def findBlobs(aiimage, pagenr):
    # Create temporary images
    img = aiimage.img
    storage = cvCreateMemStorage(0)

    gray = cvCreateImage(cvSize(img.width, img.height), 8, 1)
    cvCvtColor( img, gray, CV_BGR2GRAY )
    
    edge1 = cvCreateImage(cvSize(img.width, img.height), 8, 1)
    edge2 = cvCreateImage(cvSize(img.width, img.height), 8, 1)    

    # Find contours and filter for the first time
    cvThreshold(gray, edge1, 220, 255, CV_THRESH_BINARY_INV)

    cvClearMemStorage( storage )
    nc, cs = cvFindContours(edge1, storage)
    for c in cs.hrange(): 
        cvDrawContours(edge2, c, CV_RGB(255,255,255), CV_RGB(255,255,255), 0, -1)

    # Second time
    cvThreshold(edge2, edge1, 220, 255, CV_THRESH_BINARY)

    cvClearMemStorage( storage )
    nc, cs = cvFindContours(edge1, storage)
    for c in cs.hrange(): 
        cvDrawContours(edge2, c, CV_RGB(255,0,0), CV_RGB(0,0,255), 0, 1)

    # Third and last time
    cvThreshold(edge2,edge1,220,255,CV_THRESH_BINARY)
    
    cvClearMemStorage( storage )

    nc, cs = cvFindContours(edge1, storage)
    lis = []
    blobnr = 0
    for c in cs.hrange(): 
        rect = cvBoundingRect(c,0)
        if (rect.width)>20 and (rect.height)>20:
            filt = cvCreateImage(cvSize(img.width, img.height), 8, 1)
            crap = cvCreateImage(cvSize(img.width, img.height), img.depth, img.nChannels)

            cvRectangle(crap, (0, 0), (img.width, img.height),CV_RGB(255,255,255), -1)

            cvDrawContours(filt, c, CV_RGB(1,1,1) ,CV_RGB(1,1,1), 0, -1)
            cvDrawContours(filt, c, CV_RGB(1,1,1) ,CV_RGB(1,1,1), 0, 2)

            cvCopy(img, crap, filt)

            lis.append(AiBlob(aiimage, rect, cvGetSubRect(crap, rect), (pagenr, blobnr)))
            del(filt, crap)
            blobnr += 1
        del(rect)

    # Clean up
    del(gray, edge1, edge2, img)
    return lis # list of blobs

def compareBlobs(blob1, blob2):
    # Constants. sum(a_n) = 1.0
    a1 = 0.1
    a2 = 0.1
    a3 = 0.1
    a4 = 0.1
    a5 = 0.2
    a6 = 0.15
    a7 = 0.05
    a8 = 0.05
    a9 = 0.15

    # Compare. x_n in [0,1]
    (x1, x2, x3) = compHist(blob1, blob2)
    x4 = compLengthArea(blob1,blob2)
    x5 = compShape(blob1,blob2)
    x6 = compareSquare(blob1, blob2)
    (x7, x8, x9) = compareHueSat(blob1, blob2)

    # p in [0,1]
    #if __debug__:
    #    print "xR:", x1, "xG:", x2, "xB:", x3, "xAL:", x4, "xS:", x5,\
    #          "xBox:", x6, "xH:", x7, "xS:", x8, "xV:", x9

    p = a1*x1 + a2*x2 + a3*x3 + a4*x4 + a5*x5 + a6*x6 + a7*x7 + a8*x8 + a9*x9
    return p

def compareSquare(blob1, blob2):
    """
    If bounding boxes proportions are differnt - blobs
    are probably not similar...
    """
    frac1 = float(blob1.imgRegion.width) / float(blob1.imgRegion.height)
    frac2 = float(blob2.imgRegion.width) / float(blob2.imgRegion.height)
    xB = min(frac1, frac2) / max(frac1, frac2)
#    print "xB: ", xB
    return xB

def compLengthArea(blob1, blob2):
    a1 = abs(cvContourArea( blob1.getShape() ))
    a2 = abs(cvContourArea( blob2.getShape() ))
    l1 = abs(cvArcLength( blob1.getShape() ))
    l2 = abs(cvArcLength( blob2.getShape() ))

    frac1 = l1/a1
    frac2 = l2/a2

    xL = min(frac1, frac2) / max(frac1, frac2)  
    #print "l1: ", l1, "l2: ", l2, "a1: ", a1, "a2: ", a2, "xL: ", xL
    return xL

def compareHueSat(blob1, blob2):
    ## blob1
    frame_size1 = cvGetSize( blob1.image )
    hue1 = cvCreateImage(frame_size1, 8, 1)
    sat1 = cvCreateImage(frame_size1, 8, 1)
    val1 = cvCreateImage(frame_size1, 8, 1) 
    hsv1 = cvCreateImage(frame_size1, 8, 3) 

    cvZero(hue1);
    cvZero(sat1);
    cvZero(val1);
    cvZero(hsv1);

    cvCvtColor(blob1.image, hsv1, CV_BGR2HSV)
    cvSplit( hsv1, hue1, sat1, val1, None ) 

    hist_hue1 = cvCreateHist( [8], CV_HIST_ARRAY, [[0.0,253.0]], 1 )
    hist_sat1 = cvCreateHist( [8], CV_HIST_ARRAY, [[0.0,253.0]], 1 )
    hist_val1 = cvCreateHist( [8], CV_HIST_ARRAY, [[0.0,253.0]], 1 )
    cvCalcHist(hue1, hist_hue1)
    cvCalcHist(sat1, hist_sat1)
    cvCalcHist(val1, hist_val1)
    cvNormalizeHist(hist_hue1, 1.0)
    cvNormalizeHist(hist_sat1, 1.0)
    cvNormalizeHist(hist_val1, 1.0)

    ## blob2
    frame_size2 = cvGetSize( blob2.image )
    hue2 = cvCreateImage(frame_size2, 8, 1)
    sat2 = cvCreateImage(frame_size2, 8, 1)
    val2 = cvCreateImage(frame_size2, 8, 1) 
    hsv2 = cvCreateImage(frame_size2, 8, 3) 

    cvZero(hue2);
    cvZero(sat2);
    cvZero(val2);
    cvZero(hsv2);

    cvCvtColor(blob2.image, hsv2, CV_BGR2HSV)
    cvSplit( hsv2, hue2, sat2, val2, None ) 

    hist_hue2 = cvCreateHist( [8], CV_HIST_ARRAY, [[0.0,253.0]], 1 )
    hist_sat2 = cvCreateHist( [8], CV_HIST_ARRAY, [[0.0,253.0]], 1 )
    hist_val2 = cvCreateHist( [8], CV_HIST_ARRAY, [[0.0,253.0]], 1 )
    cvCalcHist(hue2, hist_hue2)
    cvCalcHist(sat2, hist_sat2)
    cvCalcHist(val2, hist_val2)
    cvNormalizeHist(hist_hue2, 1.0)
    cvNormalizeHist(hist_sat2, 1.0)
    cvNormalizeHist(hist_val2, 1.0)

    ## Compare
    xH = cvCompareHist(hist_hue1, hist_hue2, CV_COMP_CORREL)
    xS = cvCompareHist(hist_sat1, hist_sat2, CV_COMP_CORREL)
    xV = cvCompareHist(hist_val1, hist_val2, CV_COMP_CORREL)
    
    ## Clean up
    del frame_size1, hue1, sat1, val1, hsv1, hist_hue1, hist_sat1, hist_val1
    del frame_size2, hue2, sat2, val2, hsv2, hist_hue2, hist_sat2, hist_val2

    if xH < 0:
        xH = 0.0
    if xH > 1:
        xH = 1.0
    if xS < 0:
        xS = 0.0
    if xS > 1:
        xS = 1.0
    if xV < 0:
        xV = 0.0
    if xV > 1:
        xV = 1.0

 #   print "xH: ", xH, "  xS: ", xS, "  xV: ", xV
    return (xH, xS, xV)

def compHist(blob1, blob2):
    ## blob1
    frame_size1 = cvGetSize( blob1.image )
    r1 = cvCreateImage(frame_size1, 8, 1)
    g1 = cvCreateImage(frame_size1, 8, 1)
    b1 = cvCreateImage(frame_size1, 8, 1) 
    cvSplit( blob1.image, r1, g1, b1, None ) 

    hist_r1 = cvCreateHist( [8], CV_HIST_ARRAY, [[0.0,253.0]], 1 )
    hist_g1 = cvCreateHist( [8], CV_HIST_ARRAY, [[0.0,253.0]], 1 )
    hist_b1 = cvCreateHist( [8], CV_HIST_ARRAY, [[0.0,253.0]], 1 )
    cvCalcHist(r1, hist_r1)
    cvCalcHist(g1, hist_g1)
    cvCalcHist(b1, hist_b1)
    cvNormalizeHist(hist_r1, 1.0)
    cvNormalizeHist(hist_g1, 1.0)
    cvNormalizeHist(hist_b1, 1.0)

    ## blob2
    frame_size2 = cvGetSize( blob2.image )
    r2 = cvCreateImage(frame_size2, 8, 1)
    g2 = cvCreateImage(frame_size2, 8, 1)
    b2 = cvCreateImage(frame_size2, 8, 1) 
    cvSplit( blob2.image, r2, g2, b2, None ) 

    hist_r2 = cvCreateHist( [8], CV_HIST_ARRAY, [[0.0,253.0]], 1 )
    hist_g2 = cvCreateHist( [8], CV_HIST_ARRAY, [[0.0,253.0]], 1 )
    hist_b2 = cvCreateHist( [8], CV_HIST_ARRAY, [[0.0,253.0]], 1 )
    cvCalcHist(r2, hist_r2)
    cvCalcHist(g2, hist_g2)
    cvCalcHist(b2, hist_b2)
    cvNormalizeHist(hist_r2, 1.0)
    cvNormalizeHist(hist_g2, 1.0)
    cvNormalizeHist(hist_b2, 1.0)

    ## Compare
    xR = cvCompareHist(hist_r1, hist_r2, CV_COMP_CORREL)
    xG = cvCompareHist(hist_g1, hist_g2, CV_COMP_CORREL)
    xB = cvCompareHist(hist_b1, hist_b2, CV_COMP_CORREL)
    
    ## Clean up
    del frame_size1, r1, g1, b1, hist_r1, hist_g1, hist_b1
    del frame_size2, r2, g2, b2, hist_r2, hist_g2, hist_b2

    if xR < 0:
        xR = 0.0
    if xR > 1:
        xR = 1.0
    if xG < 0:
        xG = 0.0
    if xG > 1:
        xG = 1.0
    if xB < 0:
        xB = 0.0
    if xB > 1:
        xB = 1.0

    # print "xR: ", xR, "  xG: ", xG, "  xB: ", xB

    return (xR, xG, xB)

def compShape(blob1, blob2):
    # Blob1
    mem1 = cvCreateMemStorage(0)
    sh1 = cvCloneSeq(blob1.getShape(), mem1)

    # Blob2
    mem2 = cvCreateMemStorage(0)
    sh2 = cvCloneSeq(blob2.getShape(), mem2)

    # Compare and fixed the value
    x = 1 - (cvMatchShapes(sh1, sh2, 1)/5)
    if x<0:
        x=0

    # Clean up
    del(mem1, sh1, mem2, sh2)
    return x

class AiBlob:
    """
       For finding blobs in images and extracting
       features from blobs. A blob is region of 
       an image.
    """

    def __init__(self, parentImage, region, img, id):
        self.parentImg = parentImage
        self.imgRegion = region
        self.image = img
        self.id = id
        self.tag = None
        self.page = None

    def getShape(self):
        storage = cvCreateMemStorage(0)
        gray = cvCreateImage(cvSize(self.image.width, self.image.height), 8, 1)
        cvCvtColor( self.image, gray, CV_BGR2GRAY )
    
        edge1 = cvCreateImage(cvSize(self.image.width, self.image.height), 8, 1)

        cvThreshold(gray, edge1, 220, 255, CV_THRESH_BINARY_INV)

        cvClearMemStorage( storage )
        nc, cs = cvFindContours(edge1, storage)

        mem1 = cvCreateMemStorage(0)

        cc = CvSeq_CvPoint()
        for c in cs.hrange():
            if c.total > cc.total:
                cc = cvCloneSeq(c, mem1)

        # Clean up
        del(edge1, gray, cs, storage, mem1)
        return cc
